﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Derbster.Domain.Test
{
    [TestClass]
    public class RosterUnitTest : ContractUnitTest
    {
        private HashSet<Skater> _testSkaters;
        private Roster _testRoster;
        private CommandManager _commandManager;
        [TestInitialize]
        public void TestInitialize()
        {
            _testSkaters = TestHelper.CreateHomeTeamSkaters("Test");
            _testRoster = new Roster("Test", "Green");
            _commandManager = new CommandManager();
            _commandManager.Clear();
        }

        [TestMethod]
        public void TestCreateNew()
        {
            var newRoster = new Roster();
            Assert.IsNotNull(newRoster);
        }

        [TestMethod]
        public void TestEquals()
        {
            var newRoster = new Roster();
            Assert.IsTrue(newRoster.Equals(newRoster));
        }

        [TestMethod]
        public void TestMethodAddCaptain()
        {
            var captain = _testSkaters.Skip(2).First();
            Assert.IsNotNull(captain);
            _testRoster.AddCaptain(captain);
            Assert.AreEqual(1,_testRoster.Count(p=>p.IsCaptain));
            Assert.AreEqual(captain, _testRoster.First(p => p.IsCaptain).Skater);
            _commandManager.Undo();
            Assert.IsFalse(_testRoster.Any(p=>p.IsCaptain));
            Assert.IsFalse(_testRoster.Any(p => p.Skater == captain));
            _commandManager.Redo();
            Assert.AreEqual(1, _testRoster.Count(p => p.IsCaptain));
            Assert.AreEqual(captain, _testRoster.First(p => p.IsCaptain).Skater);
        }

        [TestMethod]
        public void TestMethodAddAndRemoveCaptain()
        {
            var captain = _testSkaters.Skip(2).First();
            Assert.IsNotNull(captain);
            _testRoster.AddCaptain(captain);
            _testRoster.RemoveCaptain();
            Assert.IsFalse(_testRoster.Any(p => p.IsCaptain));
            Assert.AreEqual(0, _testRoster.Count());
            _commandManager.Undo();
            Assert.IsTrue(_testRoster.Any(p => p.IsCaptain));
            Assert.IsTrue(_testRoster.Any(p => p.Skater == captain));
            _commandManager.Redo();
            Assert.IsFalse(_testRoster.Any(p => p.IsCaptain));
            Assert.AreEqual(0, _testRoster.Count());
        }

        [TestMethod]
        public void TestMethodAddCaptainTwice()
        {
            bool throws = false;
            var captain = _testSkaters.Skip(2).First();
            var captain2 = _testSkaters.Skip(4).First();
            Assert.IsNotNull(captain);
            _testRoster.AddCaptain(captain);
            try
            {
                _testRoster.AddCaptain(captain2);
            }
            catch (Exception)
            {
                throws = true;
            }
            Assert.IsTrue(throws);
        }

        [TestMethod]
        public void TestMethodAddCaptainSkater()
        {
            bool throws = false;
            var captain = _testSkaters.Skip(2).First(); 
            Assert.IsNotNull(captain);
            _testRoster.AddSkater(captain);
            try
            {
                _testRoster.AddCaptain(captain);
            }
            catch (Exception)
            {
                throws = true;
            }
            Assert.IsTrue(throws);
        }

        [TestMethod]
        public void TestMethodAddSkater()
        {
            var skater = _testSkaters.Skip(4).First();
            Assert.IsNotNull(skater);
            _testRoster.AddSkater(skater);
            Assert.AreEqual(0, _testRoster.Count(p => p.IsCaptain));
            Assert.AreEqual(1, _testRoster.Count());
            Assert.IsTrue(_testRoster.Any(p=>p.Skater == skater));
            _commandManager.Undo();
            Assert.AreEqual(0, _testRoster.Count(p => p.IsCaptain));
            Assert.AreEqual(0, _testRoster.Count());
            Assert.IsFalse(_testRoster.Any(p => p.Skater == skater));
            _commandManager.Redo();
            Assert.AreEqual(0, _testRoster.Count(p => p.IsCaptain));
            Assert.AreEqual(1, _testRoster.Count());
            Assert.IsTrue(_testRoster.Any(p => p.Skater == skater));
        }

        [TestMethod]
        public void TestMethodAddAndRemoveSkater()
        {
            var skater = _testSkaters.Skip(2).First();
            Assert.IsNotNull(skater);
            _testRoster.AddSkater(skater);
            _testRoster.RemoveSkater(skater);
            Assert.IsFalse(_testRoster.Any(p => p.Skater == skater));
            Assert.AreEqual(0, _testRoster.Count());
            _commandManager.Undo();
            Assert.IsTrue(_testRoster.Any(p => p.Skater == skater));
            _commandManager.Redo();
            Assert.IsFalse(_testRoster.Any(p => p.Skater == skater));
            Assert.AreEqual(0, _testRoster.Count());
        }

        [TestMethod]
        public void TestMethodAddTwoSkater()
        {
            var skater = _testSkaters.Skip(4).First();
            Assert.IsNotNull(skater);
            _testRoster.AddSkater(skater);
            var skater2 = _testSkaters.Skip(7).First();
            Assert.IsNotNull(skater2);
            _testRoster.AddSkater(skater2);
            Assert.AreEqual(0, _testRoster.Count(p => p.IsCaptain));
            Assert.AreEqual(2, _testRoster.Count());
            Assert.IsTrue(_testRoster.Any(p => p.Skater == skater));
            Assert.IsTrue(_testRoster.Any(p => p.Skater == skater2));
            _commandManager.Undo();
            Assert.AreEqual(0, _testRoster.Count(p => p.IsCaptain));
            Assert.AreEqual(1, _testRoster.Count());
            Assert.IsTrue(_testRoster.Any(p => p.Skater == skater));
            Assert.IsFalse(_testRoster.Any(p => p.Skater == skater2));
            _commandManager.Redo();
            Assert.AreEqual(0, _testRoster.Count(p => p.IsCaptain));
            Assert.AreEqual(2, _testRoster.Count());
            Assert.IsTrue(_testRoster.Any(p => p.Skater == skater2));
        }

        [TestMethod]
        public void TestMethodAddSkaterTwice()
        {
            bool throws = false;
            var skater = _testSkaters.Skip(2).First();
            Assert.IsNotNull(skater);
            _testRoster.AddSkater(skater);
            try
            {
                _testRoster.AddSkater(skater);
            }
            catch (Exception)
            {
                throws = true;
            }
            Assert.IsTrue(throws);
        }
    }
}
